package com.example.administrator.appstpremvpdemo.helper;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.util.Log;

import com.example.administrator.appstpremvpdemo.common.MainApplication;
import com.example.administrator.appstpremvpdemo.manager.LocalActivityManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

/**
 * @Author Administrator
 * @Date 2017/12/12
 * @description 有异常, 应用崩掉了是不是.但我们平常的手机应用你看过这样子的么..好像没有吧,
 * 我印象中没看过.那你觉得是它们写的程序没有bug么,这不可能吧.就算经过了严格的测试环节应该
 * 还是有那些很难发觉的bug吧.但为什么没有出现这种效果呢.这时候就归功于我们的全集异常捕获器
 * UncaughtExceptionHandler了,应用崩掉会出现这个黑色的提示框是因为安卓系统给我们的应用设
 * 置了默认的全局异常捕获器,怎么证明呢,那我们就来改变全局异常捕获器,UncaughtExceptionHandler
 * 它是一个接口,我们创建一个类来实现它
 * @function 全局异常处理类
 */

public class CauchExceptionHandler implements Thread.UncaughtExceptionHandler {

    private static final String TAG = "Activity";
    private static CauchExceptionHandler sCauchExceptionHandler = null;
    private static final String SDCARD_ROOT = Environment.getExternalStorageDirectory().toString();

    private CauchExceptionHandler() {
    }

    public static CauchExceptionHandler getInstance() {
        if (sCauchExceptionHandler == null) {
            synchronized (CauchExceptionHandler.class) {
                if (sCauchExceptionHandler == null) {
                    sCauchExceptionHandler = new CauchExceptionHandler();
                }
            }
        }
        return sCauchExceptionHandler;
    }

    /**
     * 在Application开始时调用
     */
    public void setDefaultUnCachExceptionHandler() {
        //设置应用默认的全局捕获异常器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 如果我们设置了应用的默认全局捕抓异常为CauchExceptionHandler的话
     * 应用没有捕抓的异常会到这里来,
     *
     * @param thread 线程
     * @param ex     异常
     *               可以在这里面上传异常信息
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        savaInfoToSD(ex);
        //这种异常会导致应用卡死，崩溃等非常不利于用户体验的现象
        //这些情况会导致内存溢出，那么这时候可以强制关闭虚机，结束栈中所有活动，释放内存
        Log.w("CauchExceptionHandler", ex.getMessage());
        LocalActivityManager.getInctance().clearAllactivity();
        Process.killProcess(android.os.Process.myPid());
        System.exit(0);
    }

    /**
     * 获取一些简单的信息,软件版本，手机版本，型号等信息存放在HashMap中
     * @return
     */
    private HashMap<String, String> obtainSimpleInfo(){
        HashMap<String, String> map = new HashMap<String, String>();
        PackageManager mPackageManager = MainApplication.getInstance().getPackageManager();
        PackageInfo mPackageInfo = null;
        try {
            mPackageInfo = mPackageManager.getPackageInfo(MainApplication.getInstance().getPackageName(), PackageManager.GET_ACTIVITIES);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        map.put("versionName", mPackageInfo.versionName);
        map.put("versionCode", "" + mPackageInfo.versionCode);

        map.put("MODEL", "" + Build.MODEL);
        map.put("SDK_INT", "" + Build.VERSION.SDK_INT);
        map.put("PRODUCT", "" +  Build.PRODUCT);

        return map;
    }

    /**
     * 获取系统未捕捉的错误信息
     * @param throwable
     * @return
     */
    private String obtainExceptionInfo(Throwable throwable) {
        StringWriter mStringWriter = new StringWriter();
        PrintWriter mPrintWriter = new PrintWriter(mStringWriter);
        throwable.printStackTrace(mPrintWriter);
        mPrintWriter.close();

        Log.e(TAG, mStringWriter.toString());
        return mStringWriter.toString();
    }

    /**
     * 保存获取的 软件信息，设备信息和出错信息保存在SDcard中
     * @param ex
     * @return
     */
    private String savaInfoToSD(Throwable ex){
        String fileName = null;
        StringBuffer sb = new StringBuffer();

        for (Map.Entry<String, String> entry : obtainSimpleInfo().entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append(" = ").append(value).append("\n");
        }

        sb.append(obtainExceptionInfo(ex));

        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            File dir = new File(SDCARD_ROOT + File.separator + "crash" + File.separator);
            if(! dir.exists()){
                dir.mkdir();
            }

            try{
                fileName = dir.toString() + File.separator + paserTime(System.currentTimeMillis()) + ".log";
                FileOutputStream fos = new FileOutputStream(fileName);
                fos.write(sb.toString().getBytes());
                fos.flush();
                fos.close();
            }catch(Exception e){
                e.printStackTrace();
            }

        }
        return fileName;
    }


    /**
     * 将毫秒数转换成yyyy-MM-dd-HH-mm-ss的格式
     * @param milliseconds
     * @return
     */
    private String paserTime(long milliseconds) {
        System.setProperty("user.timezone", "Asia/Shanghai");
        TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
        TimeZone.setDefault(tz);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        String times = format.format(new Date(milliseconds));

        return times;
    }
}
